Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / backend / identity_manager.py

Displaying Raw • Download


meshchatx/src/backend/identity_manager.py 9f75e3db181925ddd253f7fb231af81f9fb8c013 (9f75e3db) Text, 11.94 KB

T8b949e# SPDX-License-Identifier: 0BSD

Tff7b72import T7ee787base64
Tff7b72import T7ee787contextlib
Tff7b72import T7ee787json
Tff7b72import T7ee787os
Tff7b72import T7ee787shutil

Tff7b72import T7ee787RNS

Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787config Tff7b72import Te6edf3ConfigDAO
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787provider Tff7b72import Te6edf3DatabaseProvider
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787schema Tff7b72import Te6edf3DatabaseSchema
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787meshchat_utils Tff7b72import Te6edf3normalize_identity_storage_hash
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787path_utils Tff7b72import Te6edf3is_path_within_dir


Tff7b72class T56d364IdentityManagerTb4b4b4:
Tff7b72def Tff7b72__init__Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3storage_dirTb4b4b4: Tffa657strTb4b4b4, Te6edf3identity_file_pathTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffstorage_dir Tff7b72= Te6edf3storage_dir
Tff7b72selfTff7b72.Td2a8ffidentity_file_path Tff7b72= Te6edf3identity_file_path

Tff7b72def Td2a8ffget_identity_bytesTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identityTb4b4b4: Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4) Tff7b72-Tff7b72> Tffa657bytesTb4b4b4:
Te6edf3private_key Tff7b72= Te6edf3identityTff7b72.Td2a8ffget_private_keyTb4b4b4(Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3private_keyTb4b4b4:
Te6edf3msg Tff7b72= Ta5d6ff"Ta5d6ffidentity has no private keyTa5d6ff"
Tff7b72raise Tf85149ValueErrorTb4b4b4(Te6edf3msgTb4b4b4)
Tff7b72return Te6edf3private_key

Tff7b72def Td2a8ffbackup_identityTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identityTb4b4b4: Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4) Tff7b72-Tff7b72> Tffa657dictTb4b4b4:
Te6edf3identity_bytes Tff7b72= Tff7b72selfTff7b72.Td2a8ffget_identity_bytesTb4b4b4(Te6edf3identityTb4b4b4)
Te6edf3target_path Tff7b72= Tff7b72selfTff7b72.Td2a8ffidentity_file_path Tff7b72or Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4,
Ta5d6ff"Ta5d6ffidentityTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffdirnameTb4b4b4(Te6edf3target_pathTb4b4b4)Tb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3target_pathTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3identity_bytesTb4b4b4)
Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Te6edf3target_pathTb4b4b4,
Ta5d6ff"Ta5d6ffsizeTa5d6ff"Tb4b4b4: Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffgetsizeTb4b4b4(Te6edf3target_pathTb4b4b4)Tb4b4b4,
Tb4b4b4}

Tff7b72def Td2a8ffbackup_identity_base32Tb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identityTb4b4b4: Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4) Tff7b72-Tff7b72> Tffa657strTb4b4b4:
Tff7b72return Te6edf3base64Tff7b72.Td2a8ffb32encodeTb4b4b4(Tff7b72selfTff7b72.Td2a8ffget_identity_bytesTb4b4b4(Te6edf3identityTb4b4b4)Tb4b4b4)Tff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)

Tff7b72def Td2a8ffget_all_identity_backup_bytesTb4b4b4(Tff7b72selfTb4b4b4) Tff7b72-Tff7b72> Tffa657dictTb4b4b4[Tffa657strTb4b4b4, Tffa657bytesTb4b4b4]Tb4b4b4:
Te6edf3result Tff7b72= Tb4b4b4{Tb4b4b4}
Te6edf3identities_base_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6ffidentitiesTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3identities_base_dirTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3result
Tff7b72for Te6edf3identity_hash Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Te6edf3identities_base_dirTb4b4b4)Tb4b4b4:
Te6edf3identity_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identities_base_dirTb4b4b4, Te6edf3identity_hashTb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3identity_pathTb4b4b4)Tb4b4b4:
Tff7b72continue
Te6edf3identity_file Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identity_pathTb4b4b4, Ta5d6ff"Ta5d6ffidentityTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisfileTb4b4b4(Te6edf3identity_fileTb4b4b4)Tb4b4b4:
Tff7b72continue
Tff7b72tryTb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3identity_fileTb4b4b4, Ta5d6ff"Ta5d6ffrbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3resultTb4b4b4[Te6edf3identity_hashTb4b4b4] Tff7b72= Te6edf3fTff7b72.Td2a8ffreadTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149OSErrorTb4b4b4:
Tff7b72continue
Tff7b72return Te6edf3result

Tff7b72def Td2a8fflist_identitiesTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3current_identity_hashTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4)Tb4b4b4:
Te6edf3identities Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3identities_base_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6ffidentitiesTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3identities_base_dirTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3identities

Tff7b72for Te6edf3identity_hash Tff7b72in Te6edf3osTff7b72.Td2a8fflistdirTb4b4b4(Te6edf3identities_base_dirTb4b4b4)Tb4b4b4:
Te6edf3identity_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identities_base_dirTb4b4b4, Te6edf3identity_hashTb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3identity_pathTb4b4b4)Tb4b4b4:
Tff7b72continue

Te6edf3metadata_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identity_pathTb4b4b4, Ta5d6ff"Ta5d6ffmetadata.jsonTa5d6ff"Tb4b4b4)
Te6edf3metadata Tff7b72= Tff7b72None
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3metadata_pathTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Tff7b72with Tffa657openTb4b4b4(Te6edf3metadata_pathTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3metadata Tff7b72= Te6edf3jsonTff7b72.Td2a8ffloadTb4b4b4(Te6edf3fTb4b4b4)

Tff7b72if Te6edf3metadataTb4b4b4:
Te6edf3identitiesTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4: Te6edf3identity_hashTb4b4b4,
Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4: Te6edf3metadataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffAnonymous PeerTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fficon_nameTa5d6ff"Tb4b4b4: Te6edf3metadataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fficon_nameTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fficon_foreground_colourTa5d6ff"Tb4b4b4: Te6edf3metadataTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6fficon_foreground_colourTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fficon_background_colourTa5d6ff"Tb4b4b4: Te6edf3metadataTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6fficon_background_colourTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fflxmf_addressTa5d6ff"Tb4b4b4: Te6edf3metadataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflxmf_addressTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fflxst_addressTa5d6ff"Tb4b4b4: Te6edf3metadataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflxst_addressTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6ffis_currentTa5d6ff"Tb4b4b4: Tb4b4b4(
Te6edf3current_identity_hash Tff7b72is Tff7b72not Tff7b72None
Tff7b72and Te6edf3identity_hash Tff7b72== Te6edf3current_identity_hash
Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72continue

T8b949e# Fallback to DB if metadata.json doesn't exist
Te6edf3db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identity_pathTb4b4b4, Ta5d6ff"Ta5d6ffdatabase.dbTa5d6ff"Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3db_pathTb4b4b4)Tb4b4b4:
Tff7b72continue

Te6edf3display_name Tff7b72= Ta5d6ff"Ta5d6ffAnonymous PeerTa5d6ff"
Te6edf3icon_name Tff7b72= Tff7b72None
Te6edf3icon_foreground_colour Tff7b72= Tff7b72None
Te6edf3icon_background_colour Tff7b72= Tff7b72None
Te6edf3lxmf_address Tff7b72= Tff7b72None
Te6edf3lxst_address Tff7b72= Tff7b72None

Tff7b72tryTb4b4b4:
Te6edf3temp_provider Tff7b72= Te6edf3DatabaseProviderTb4b4b4(Te6edf3db_pathTb4b4b4)
Te6edf3temp_config_dao Tff7b72= Te6edf3ConfigDAOTb4b4b4(Te6edf3temp_providerTb4b4b4)
Te6edf3display_name Tff7b72= Te6edf3temp_config_daoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffAnonymous PeerTa5d6ff"Tb4b4b4)
Te6edf3icon_name Tff7b72= Te6edf3temp_config_daoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflxmf_user_icon_nameTa5d6ff"Tb4b4b4)
Te6edf3icon_foreground_colour Tff7b72= Te6edf3temp_config_daoTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6fflxmf_user_icon_foreground_colourTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3icon_background_colour Tff7b72= Te6edf3temp_config_daoTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6fflxmf_user_icon_background_colourTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3lxmf_address Tff7b72= Te6edf3temp_config_daoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflxmf_address_hashTa5d6ff"Tb4b4b4)
Te6edf3lxst_address Tff7b72= Te6edf3temp_config_daoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflxst_address_hashTa5d6ff"Tb4b4b4)
Te6edf3temp_providerTff7b72.Td2a8ffclose_allTb4b4b4(Tb4b4b4)

T8b949e# Save metadata for next time
Te6edf3metadata Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4: Te6edf3display_nameTb4b4b4,
Ta5d6ff"Ta5d6fficon_nameTa5d6ff"Tb4b4b4: Te6edf3icon_nameTb4b4b4,
Ta5d6ff"Ta5d6fficon_foreground_colourTa5d6ff"Tb4b4b4: Te6edf3icon_foreground_colourTb4b4b4,
Ta5d6ff"Ta5d6fficon_background_colourTa5d6ff"Tb4b4b4: Te6edf3icon_background_colourTb4b4b4,
Ta5d6ff"Ta5d6fflxmf_addressTa5d6ff"Tb4b4b4: Te6edf3lxmf_addressTb4b4b4,
Ta5d6ff"Ta5d6fflxst_addressTa5d6ff"Tb4b4b4: Te6edf3lxst_addressTb4b4b4,
Tb4b4b4}
Tff7b72with Tffa657openTb4b4b4(Te6edf3metadata_pathTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3jsonTff7b72.Td2a8ffdumpTb4b4b4(Te6edf3metadataTb4b4b4, Te6edf3fTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError reading config for Tffd700{Te6edf3identity_hashTffd700}Ta5d6ff: Tffd700{Te6edf3eTffd700}Ta5d6ff"Tb4b4b4)

Te6edf3identitiesTff7b72.Td2a8ffappendTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4: Te6edf3identity_hashTb4b4b4,
Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4: Te6edf3display_nameTb4b4b4,
Ta5d6ff"Ta5d6fficon_nameTa5d6ff"Tb4b4b4: Te6edf3icon_nameTb4b4b4,
Ta5d6ff"Ta5d6fficon_foreground_colourTa5d6ff"Tb4b4b4: Te6edf3icon_foreground_colourTb4b4b4,
Ta5d6ff"Ta5d6fficon_background_colourTa5d6ff"Tb4b4b4: Te6edf3icon_background_colourTb4b4b4,
Ta5d6ff"Ta5d6fflxmf_addressTa5d6ff"Tb4b4b4: Te6edf3lxmf_addressTb4b4b4,
Ta5d6ff"Ta5d6fflxst_addressTa5d6ff"Tb4b4b4: Te6edf3lxst_addressTb4b4b4,
Ta5d6ff"Ta5d6ffis_currentTa5d6ff"Tb4b4b4: Tb4b4b4(
Te6edf3current_identity_hash Tff7b72is Tff7b72not Tff7b72None
Tff7b72and Te6edf3identity_hash Tff7b72== Te6edf3current_identity_hash
Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3identities

Tff7b72def Td2a8ffcreate_identityTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3display_nameTff7b72=Tff7b72NoneTb4b4b4)Tb4b4b4:
Te6edf3new_identity Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTb4b4b4(Te6edf3create_keysTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72return Tff7b72selfTff7b72.Td2a8ff_save_new_identityTb4b4b4(Te6edf3new_identityTb4b4b4, Te6edf3display_name Tff7b72or Ta5d6ff"Ta5d6ffAnonymous PeerTa5d6ff"Tb4b4b4)

Tff7b72def Td2a8ff_save_new_identityTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identityTb4b4b4, Te6edf3display_nameTb4b4b4)Tb4b4b4:
Te6edf3identity_hash Tff7b72= Te6edf3identityTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)

Te6edf3identity_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6ffidentitiesTa5d6ff"Tb4b4b4, Te6edf3identity_hashTb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Te6edf3identity_dirTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)

Te6edf3identity_file Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identity_dirTb4b4b4, Ta5d6ff"Ta5d6ffidentityTa5d6ff"Tb4b4b4)
Tff7b72with Tffa657openTb4b4b4(Te6edf3identity_fileTb4b4b4, Ta5d6ff"Ta5d6ffwbTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3fTff7b72.Td2a8ffwriteTb4b4b4(Te6edf3identityTff7b72.Td2a8ffget_private_keyTb4b4b4(Tb4b4b4)Tb4b4b4)

Te6edf3db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identity_dirTb4b4b4, Ta5d6ff"Ta5d6ffdatabase.dbTa5d6ff"Tb4b4b4)

Te6edf3new_provider Tff7b72= Te6edf3DatabaseProviderTb4b4b4(Te6edf3db_pathTb4b4b4)
Te6edf3new_schema Tff7b72= Te6edf3DatabaseSchemaTb4b4b4(Te6edf3new_providerTb4b4b4)
Te6edf3new_schemaTff7b72.Td2a8ffinitializeTb4b4b4(Tb4b4b4)

Tff7b72if Te6edf3display_nameTb4b4b4:
Te6edf3new_config_dao Tff7b72= Te6edf3ConfigDAOTb4b4b4(Te6edf3new_providerTb4b4b4)
Te6edf3new_config_daoTff7b72.Td2a8ffsetTb4b4b4(Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4, Te6edf3display_nameTb4b4b4)

Te6edf3new_providerTff7b72.Td2a8ffclose_allTb4b4b4(Tb4b4b4)

T8b949e# Preserve icon/address metadata when re-importing an existing identity.
Te6edf3metadata_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identity_dirTb4b4b4, Ta5d6ff"Ta5d6ffmetadata.jsonTa5d6ff"Tb4b4b4)
Te6edf3existing_metadata Tff7b72= Tb4b4b4{Tb4b4b4}
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3metadata_pathTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4, Tffa657openTb4b4b4(Te6edf3metadata_pathTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3loaded Tff7b72= Te6edf3jsonTff7b72.Td2a8ffloadTb4b4b4(Te6edf3fTb4b4b4)
Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3loadedTb4b4b4, Tffa657dictTb4b4b4)Tb4b4b4:
Te6edf3existing_metadata Tff7b72= Te6edf3loaded

Te6edf3resolved_name Tff7b72= Tb4b4b4(
Tb4b4b4(Te6edf3display_name Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
Tff7b72or Te6edf3existing_metadataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4)
Tff7b72or Ta5d6ff"Ta5d6ffAnonymous PeerTa5d6ff"
Tb4b4b4)
Te6edf3metadata Tff7b72= Tb4b4b4{
Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4: Te6edf3resolved_nameTb4b4b4,
Ta5d6ff"Ta5d6fficon_nameTa5d6ff"Tb4b4b4: Te6edf3existing_metadataTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fficon_nameTa5d6ff"Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fficon_foreground_colourTa5d6ff"Tb4b4b4: Te6edf3existing_metadataTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6fficon_foreground_colourTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Ta5d6ff"Ta5d6fficon_background_colourTa5d6ff"Tb4b4b4: Te6edf3existing_metadataTff7b72.Td2a8ffgetTb4b4b4(
Ta5d6ff"Ta5d6fficon_background_colourTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4}
Tff7b72for Te6edf3key Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6fflxmf_addressTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fflxst_addressTa5d6ff"Tb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3key Tff7b72in Te6edf3existing_metadataTb4b4b4:
Te6edf3metadataTb4b4b4[Te6edf3keyTb4b4b4] Tff7b72= Te6edf3existing_metadataTb4b4b4[Te6edf3keyTb4b4b4]

Tff7b72with Tffa657openTb4b4b4(Te6edf3metadata_pathTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3jsonTff7b72.Td2a8ffdumpTb4b4b4(Te6edf3metadataTb4b4b4, Te6edf3fTb4b4b4)

Tff7b72return Tb4b4b4{
Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4: Te6edf3identity_hashTb4b4b4,
Ta5d6ff"Ta5d6ffdisplay_nameTa5d6ff"Tb4b4b4: Te6edf3resolved_nameTb4b4b4,
Tb4b4b4}

Tff7b72def Td2a8ffupdate_metadata_cacheTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identity_hashTb4b4b4: Tffa657strTb4b4b4, Te6edf3metadataTb4b4b4: Tffa657dictTb4b4b4)Tb4b4b4:
Te6edf3identity_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6ffidentitiesTa5d6ff"Tb4b4b4, Te6edf3identity_hashTb4b4b4)
Tff7b72if Tff7b72not Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3identity_dirTb4b4b4)Tb4b4b4:
Tff7b72return

Te6edf3metadata_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identity_dirTb4b4b4, Ta5d6ff"Ta5d6ffmetadata.jsonTa5d6ff"Tb4b4b4)

T8b949e# Merge with existing metadata if it exists
Te6edf3existing_metadata Tff7b72= Tb4b4b4{Tb4b4b4}
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffexistsTb4b4b4(Te6edf3metadata_pathTb4b4b4)Tb4b4b4:
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4, Tffa657openTb4b4b4(Te6edf3metadata_pathTb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3existing_metadata Tff7b72= Te6edf3jsonTff7b72.Td2a8ffloadTb4b4b4(Te6edf3fTb4b4b4)

Te6edf3existing_metadataTff7b72.Td2a8ffupdateTb4b4b4(Te6edf3metadataTb4b4b4)

Tff7b72with Tffa657openTb4b4b4(Te6edf3metadata_pathTb4b4b4, Ta5d6ff"Ta5d6ffwTa5d6ff"Tb4b4b4) Tff7b72as Te6edf3fTb4b4b4:
Te6edf3jsonTff7b72.Td2a8ffdumpTb4b4b4(Te6edf3existing_metadataTb4b4b4, Te6edf3fTb4b4b4)

Tff7b72def Td2a8ffdelete_identityTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3identity_hashTb4b4b4: Tffa657strTb4b4b4, Te6edf3current_identity_hashTb4b4b4: Tffa657str Tff7b72| Tff7b72NoneTb4b4b4)Tb4b4b4:
Te6edf3canonical Tff7b72= Te6edf3normalize_identity_storage_hashTb4b4b4(Te6edf3identity_hashTb4b4b4)
Tff7b72if Tff7b72not Te6edf3canonicalTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffInvalid identity hashTa5d6ff"Tb4b4b4)
Te6edf3current_canonical Tff7b72= Te6edf3normalize_identity_storage_hashTb4b4b4(Te6edf3current_identity_hash Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tff7b72if Te6edf3current_canonical Tff7b72and Te6edf3canonical Tff7b72== Te6edf3current_canonicalTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffCannot delete the current active identityTa5d6ff"Tb4b4b4)

Te6edf3identities_root Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8ffstorage_dirTb4b4b4, Ta5d6ff"Ta5d6ffidentitiesTa5d6ff"Tb4b4b4)
Te6edf3identity_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Te6edf3identities_rootTb4b4b4, Te6edf3canonicalTb4b4b4)
Tff7b72if Tff7b72not Te6edf3is_path_within_dirTb4b4b4(Te6edf3identity_dirTb4b4b4, Te6edf3identities_rootTb4b4b4)Tb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffInvalid identity hashTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffisdirTb4b4b4(Te6edf3identity_dirTb4b4b4)Tb4b4b4:
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Te6edf3identity_dirTb4b4b4)
Tff7b72return Tff7b72True
Tff7b72return Tff7b72False

Te6edf3_MAX_IDENTITY_BYTES Tff7b72= T79c0ff65536

Tff7b72def Td2a8ffrestore_identity_from_bytesTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3identity_bytesTb4b4b4: Tffa657bytesTb4b4b4,
Te6edf3display_nameTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657dictTb4b4b4:
Tff7b72if Tff7b72not Te6edf3identity_bytesTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffIdentity file is emptyTa5d6ff"Tb4b4b4)
Tff7b72if Tffa657lenTb4b4b4(Te6edf3identity_bytesTb4b4b4) Tff7b72> Tff7b72selfTff7b72.Td2a8ff_MAX_IDENTITY_BYTESTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffIdentity file is too largeTa5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
T8b949e# We use RNS.Identity.from_bytes to validate and get the hash
Te6edf3identity Tff7b72= Te6edf3RNSTff7b72.Td2a8ffIdentityTff7b72.Td2a8fffrom_bytesTb4b4b4(Te6edf3identity_bytesTb4b4b4)
Tff7b72if Tff7b72not Te6edf3identityTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffCould not load identity from bytesTa5d6ff"Tb4b4b4)

Te6edf3name Tff7b72= Tb4b4b4(Te6edf3display_name Tff7b72or Ta5d6ff"Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4) Tff7b72or Ta5d6ff"Ta5d6ffRestored IdentityTa5d6ff"
Tff7b72return Tff7b72selfTff7b72.Td2a8ff_save_new_identityTb4b4b4(Te6edf3identityTb4b4b4, Te6edf3nameTb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72raise
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffFailed to restore identity: Tffd700{Te6edf3excTffd700}Ta5d6ff"Tb4b4b4) Tff7b72from T7ee787exc

Tff7b72def Td2a8ffrestore_identity_from_base32Tb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3base32_valueTb4b4b4: Tffa657strTb4b4b4,
Te6edf3display_nameTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72NoneTb4b4b4,
Tb4b4b4) Tff7b72-Tff7b72> Tffa657dictTb4b4b4:
Tff7b72if Te6edf3base32_value Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffbase32 value is requiredTa5d6ff"Tb4b4b4)
Te6edf3normalized Tff7b72= Ta5d6ff"Ta5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Tffa657strTb4b4b4(Te6edf3base32_valueTb4b4b4)Tff7b72.Td2a8ffsplitTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3normalizedTb4b4b4:
Tff7b72raise Tf85149ValueErrorTb4b4b4(Ta5d6ff"Ta5d6ffbase32 value is requiredTa5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3identity_bytes Tff7b72= Te6edf3base64Tff7b72.Td2a8ffb32decodeTb4b4b4(Te6edf3normalizedTb4b4b4, Te6edf3casefoldTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3excTb4b4b4:
Te6edf3msg Tff7b72= Ta5d6fffTa5d6ff"Ta5d6ffInvalid base32 identity: Tffd700{Te6edf3excTffd700}Ta5d6ff"
Tff7b72raise Tf85149ValueErrorTb4b4b4(Te6edf3msgTb4b4b4) Tff7b72from T7ee787exc
Tff7b72return Tff7b72selfTff7b72.Td2a8ffrestore_identity_from_bytesTb4b4b4(
Te6edf3identity_bytesTb4b4b4,
Te6edf3display_nameTff7b72=Te6edf3display_nameTb4b4b4,
Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────